/*
 * Copyright (c) 2009 LastFM.Desktop Anton Pavlik.
 * All Rights Reserved.
 * 
 * You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, 
 * with or without modifications, and in Source or Object form, provided that You meet the following 
 * conditions:
 * 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
 *
 * 2. You must cause any modified files to carry prominent notices stating that You changed the files; 
 * and
 *
 * 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, 
 * patent, trademark, and attribution notices from the Source form of the Work, excluding those notices 
 * that do not pertain to any part of the Derivative Works.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * You may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 *
 * Unless required by applicable law or agreed to in writing, Licensor provides the Work 
 * (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 * CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties 
 * or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. 
 * YOU ARE SOLELY RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF USING OR REDISTRIBUTING THE WORK
 * AND ASSUME ANY RISKS ASSOCIATED WITH YOUR EXERCISE OF PERMISSIONS UNDER THIS LICENSE. 
 */
package org.shake.lastfm.api.method;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;

import org.apache.commons.digester.Digester;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
import org.apache.xmlrpc.client.XmlRpcCommonsTransportFactory;

public class MethodExecutor
{
    private static final String SERVER_URL = "http://ws.audioscrobbler.com/2.0/";
    
    private Digester digester;
    
    public MethodExecutor()
    {
        this.digester = new Digester();
        this.digester.setValidating(false);
    }
    
    private XmlRpcClient createClient()
    {
        XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
        try
        {
            config.setServerURL(new URL(SERVER_URL));
        } catch (MalformedURLException e)
        {
            e.printStackTrace();
        }
        XmlRpcClient client = new XmlRpcClient();
        client.setTransportFactory(new XmlRpcCommonsTransportFactory(client));
        client.setConfig(config);
        
        return client;
    }
    
    private Map<String, String> createExecParameters(Map<XmlRpcMethodParamName, String> parameters)
    {
        Map<String, String> result = new HashMap<String, String>();
        for (Entry<XmlRpcMethodParamName, String> entry : parameters.entrySet())
        {
            result.put(entry.getKey().getName(), entry.getValue());
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    public <ResultType> ResultType executeMethod(final XmlRpcMethodName methodName, final Map<XmlRpcMethodParamName, String> parameters) throws XmlRpcMethodException
    {
        ResultType result = null;
        try
        {
            XmlRpcClient client = createClient();
            XmlRpcMethodConfig methodConfig = MethodConfigLoader.loadMethodConfig(methodName);
            Object callResult = client.execute(methodName.getName(), new Object[]{createExecParameters(parameters)});
            
            synchronized ( this.digester )
            {
                methodConfig.configureDigester(this.digester);
                
                File temp = File.createTempFile("tmp", methodName.getName());
                temp.deleteOnExit();

                FileOutputStream out = null;
                try
                {
                    out = new FileOutputStream(temp);
                    
                    String res = callResult.toString().replaceAll(Matcher.quoteReplacement("\\\""), "\"");
                    res = res.replaceAll(Matcher.quoteReplacement("\\\'"), "\'");
                    
                    out.write(res.getBytes("utf-8"));
                    out.close();
                }
                finally
                {
                    try
                    {
                        out.close();
                    } catch(Exception ex){}
                }
                
                result = (ResultType) this.digester.parse(new FileInputStream(temp));
            }
        } catch (Exception e)
        {
            throw new XmlRpcMethodException(e);
        }
        
        return result;
    }

}